import {
  Body,
  Controller,
  ForbiddenException,
  Get,
  Param,
  Post,
  UseGuards
} from '@nestjs/common'
import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard'
import { User } from 'src/users/entities/user.entity'
import { CurrentUser } from 'src/common/user.decorator'
import { InjectRepository } from '@nestjs/typeorm'
import { Repository } from 'typeorm'
import { CreateOrderDto } from './dto/create-order.dto'
import { Item, ItemStatus } from 'src/items/entities/item.entity'
import { OrdersService } from './orders.service'
import { Address } from 'src/users/entities/address.entity'
import { OrderStatus } from './entities/order.entity'

@UseGuards(JwtAuthGuard)
@Controller('api/orders')
export class OrdersController {
  constructor(
    private readonly service: OrdersService,
    @InjectRepository(Item)
    public itemsRepository: Repository<Item>,
    @InjectRepository(User)
    public usersRepository: Repository<User>,
    @InjectRepository(Address)
    public addressesRepository: Repository<Address>
  ) {}

  @Get(':id')
  async getOne(@Param('id') id: string, @CurrentUser() user: User) {
    // TODO: 隐藏其他 user 中的 mobile 等敏感字段
    return await this.service.repo.find({
      where: {
        id,
        user: {
          id: user.id
        }
      },
      relations: ['item', 'seller', 'user', 'address']
    })
  }

  @Get()
  async getAll(@CurrentUser() user: User) {
    return await this.service.repo.find({
      where: {
        user: {
          id: user.id
        }
      },
      relations: ['item', 'seller']
    })
  }

  @Post('')
  async createOne(@Body() dto: CreateOrderDto, @CurrentUser() user: User) {
    const item = await this.itemsRepository.findOneOrFail(dto.itemId, {
      relations: ['user']
    })
    const address = await this.addressesRepository.findOneOrFail(dto.addressId)

    if (item.status !== ItemStatus.AVAILABLE) {
      throw new ForbiddenException('商品不可购买')
    }

    try {
      // TODO: 事务和数据库锁
      await this.itemsRepository.update(item.id, {
        status: ItemStatus.SOLD
      })

      const order = await this.service.repo.save({
        itemPrice: item.price,
        shippingFee: item.shippingFee ?? 0,
        status: OrderStatus.PENDING,
        item,
        seller: item.user,
        user,
        address
      })
      // TODO: select fields
      return await this.getOne(order.id, user)
    } catch (err) {
      await this.itemsRepository.update(item.id, {
        status: ItemStatus.AVAILABLE
      })
      throw err
    }
  }
}
